home *** CD-ROM | disk | FTP | other *** search
-
- /******************************************************************************
-
- MODULE
- tplter.c
-
- DESCRIPTION
- ein kleines kommando, welches
- ein Templatefile einliest,
- das bestimmte Platzhalter enthaelt
- und dann das verwendbare Ergebnis
- in den aktuellen Text einbindet.
-
- NOTES
- * for XDME some features of flexprintf were commented out
- * that module is highly experimental
-
- BUGS
- ?
-
- TODO
- * linenumber in read_file
- * check for success in flexprintf
- * flexSCANf needs to be created - but that thing needs a
- little bit more work, since we can't parse line by line
- * another version of that module might support loops, conditionals
- and subtemplates - lets see
-
- EXAMPLES
-
- SEE ALSO
-
- INDEX
-
- HISTORY
- 17-08-93 b_noll created
- 18-08-93 b_noll xdme-interface
- 15-06-94 b_noll added another flexprintf-version
- 15-08-94 b_noll added to the 1.83.** tree (no DynCom features)
- 01-10-94 b_noll introduced DEFMESSAGE
-
- PRIVATE
- we need access to the following functions:
- do_command();
- do_insertwrite();
- getvar();
- COM_Add(), COM_Lock(), COM_Remove()
-
- fopen, fclose, xefgets may be replaced by Dos-Based Open, Close, [own-creation]
- malloc && free may be replaced by Exec-Based AllocVec, FreeVec
-
- structures:
- globalflags;
- Ep;
- av
-
- ******************************************************************************/
-
- /**************************************
- Includes
- **************************************/
-
- #include "defs.h"
- /* #include "COM.h" */
- /* #include "libs/AUTO.h" */
-
- /**************************************
- Global Variables
- **************************************/
-
-
- /**************************************
- Internal Defines & Structures
- **************************************/
-
- /* we do not need that structure in XDME */
- #ifndef STREAM
- #define STREAM APTR
- #endif /* STREAM */
-
- /**************************************
- Internal Variables
- **************************************/
-
- static const char * mod_name = "Templater";
-
- /**************************************
- Internal Prototypes
- **************************************/
-
- BOOL flexprintf (STREAM*, BOOL (*)(STREAM*, STRPTR), STRPTR, STREAM*, STRPTR (*)(STREAM*, STRPTR));
- char* mygetv (APTR* , char* );
- BOOL myfputs (FILE** , char* );
-
- /**************************************
- Macros
- **************************************/
- //DEFMESSAGE( _TPLT_no_memory, "No Memory\n" )
- //DEFMESSAGE( _TPLT_no_query_name, "No name given" )
- DEFMESSAGE( _TPLT_file_not_found, "File not found" )
- //DEFMESSAGE( _TPLT_unexpected_end_of_query, "Unterminated variable query" )
- //DEFMESSAGE( _TPLT_no_query_result, "No value for variable" )
- #define ERROR_NO_NAME_OF_QUERY /* error ("%s:\n%s!\n", mod_name, _TPLT_no_query_name); */
- #define ERROR_NO_VALUE_OF_QUERY /* error ("s:\n%s %s!\n", mod_name, _TPLT_no_query_result, memo); */
- #define ERROR_UNTERMINATED_QUERY /* error ("%s:\n%s!\n", mod_name, _TPLT_unexpected_end_of_query ) */
- #define ERROR_NO_FILE error ("%s:\n%s %s!\n", mod_name, _TPLT_file_not_found, name);
- #define ERROR_NO_MEMORY /* error ("%s:\n%s!\n", mod_name, _TPLT_no_memory); */
-
- #define INC(x) ++(x)
- #define DEC(x) --(x)
-
-
- /* MACROS 18-08-93 by b_noll */
- #define is_char(x) (isalnum(x) || ((x) == '_') || ((x) == '.'))
- #define is_command(x) (is_varstart(*(x)) && (*(x) == (x)[1]))
- #define is_comment(x) (*(x) == '#')
-
-
- /* ---- definitions for "is_varstart" */
- #ifdef SLOW_VARSTART
- # define is_varstart(x) strchr(query_starts, x)
- #else
- # define is_varstart(x) (((x) == '$') || ((x) == '%'))
- /* ((x) == '%') */ /* <<< use that line to enable only '%'-variables */
- /* ((x) == '$') */ /* <<< use that line to enable only '$'-variables */
- /* (((x) == '$') || ((x) == '%')) */ /* <<< use that line to enable '$' or '%'-variables */
- #endif
-
-
- /* ---- definitions for query-recognition */
- #define QUERY_START "%$" /* <<< this line only has affect if SLOW_VARSTART is defined */
-
- /* ---- definitions for bracket-recognition */
- #ifdef AMIGA
- # define BRACKET_OPEN "(`[{<\253" /* the last one is '<<' */
- # define BRACKET_CLOSE ")']}>\273" /* the last one is '>>' */
- #else
- # define BRACKET_OPEN "(`[{<"
- # define BRACKET_CLOSE ")']}>"
- #endif /* AMIGA */
-
-
-
- #ifdef XDME
-
- /* ---- XDME uses a subset of the possibles methods; */
- /* we currently do only allow $(...) and $`...' */
- /* to be recognized and replaced */
- # undef SLOW_VARSTART
- # undef is_varstart
- # undef QUERY_START
- # undef BRACKET_OPEN
- # undef BRACKET_CLOSE
-
-
- # define is_varstart(x) ((x) == '$')
- # define QUERY_START "$"
- # define BRACKET_OPEN "(`"
- # define BRACKET_CLOSE ")'"
-
- #endif /* XDME */
-
- /**************************************
- Implementation
- **************************************/
-
-
-
-
-
- /* ---- there are currently 2 Versions of flexprintf here;
- ** the first - older - version was used over 'bout 1/2 a year
- ** and did not show any error; the second one is not yet really
- ** tested w/ "XDME", it was used with "Nyktos Ophthalmoi" for
- ** 'bout 2 months.
- ** please do't ask me, why I created 2nd version, there was
- ** a reason, but I can't remember ... */
-
- #ifdef OLD
-
-
- /*****************************************************************************
-
- NAME
- flexprintf
-
- PARAMETER
- STREAM*outstream;
- ;BOOL (*writechar) (STREAM*, char);
- BOOL (*writestring)(STREAM*, STRPTR);
- STRPTR format;
- STREAM*instream;
- STRPTR (*getstring)(STREAM*, STRPTR);
-
- RESULT
- success
-
- RETURN
- BOOL;
-
- DESCRIPTION
- similar to C_sprintf but slightly different.
-
- wir parsen ein template, das
- $(...) oder %(...) oder ${...} oder %{...} oder
- $«...» oder %«...» oder $<...> oder %<...> oder
- $[...] oder %[...] oder $`...' oder %`...'
- als signalworte hat;
- was zwischen den Klammern steht, wird an
- getstring uebergeben; dessen Ergebnis
- (wir erwarten IMMER strings) wird dann
- eingesetzt.
-
- man kann die Funktion auf 2 sehr unterschiediche
- Weisen verwenden:
- wie sprintf - in diesem Falle ignoriert die
- getfunktion das 2. Argument sondern gibt jedesmal den
- "naechsten" wert zurueck
- wie hier gedacht - in diesem falle liest die getfunktion
- aus einem baum o.ae. den Wert, der der namen von arg2 traegt.
-
- NOTES
- STREAM == APTR
- format must not be const!
-
- not like in normal XDME-scripts there MUST be a form
- of quotes around any variable!
- for XDME "%" and "<...>" "«...»" "[...]" "{...}" were
- disabled.
-
- BUGS
- we do ignore the result of our writestring
- and we do always return TRUE
- (to fix - change "writestring..."
- into "if (!writestring...) return (FALSE);")
-
- EXAMPLES
-
- SEE ALSO
-
- INTERNALS
-
- HISTORY
- 21-07-93 b_noll created
- 18-08-93 b_noll modified for XDME
-
- ******************************************************************************/
-
- BOOL flexprintf (STREAM* outstream, BOOL (*writestring)(STREAM*, STRPTR), STRPTR format, STREAM* instream, STRPTR (*getstring)(STREAM*, STRPTR))
- {
- char * cptr = format;
- unsigned char curr;
- unsigned char attn = 0;
-
- for (; (curr = *format) != 0; ++format) {
- if (is_varstart(curr)) {
- if (attn) *cptr = attn;
- *format = 0;
- writestring (outstream, cptr);
- cptr = format;
- attn = curr;
- continue;
- } /* if */
-
- if (attn) {
- char scan = 0;
-
- switch (curr) {
- /* some inconsistancies to XDME were commented out */
- /* case '[': scan = ']'; break; */
- /* case '«': scan = '»'; break; */
- /* case '<': scan = '>'; break; */
- /* case '{': scan = '}'; break; */
- case '(': scan = ')'; break;
- case '`': scan = '\''; break;
- } /* switch */
-
- if (scan) {
- char * memo;
- char * rslt;
-
- ++format;
- memo = format;
- while ((curr = *format) && !(curr == scan)) {
- ++format;
- } /* while */
-
- *format = 0;
- if (*memo) {
- rslt = getstring (instream, memo);
- if (rslt) {
- writestring (outstream, rslt);
-
- *format = scan;
- attn = 0;
- cptr = format+1;
- continue;
-
- } else {
- ERROR_NO_VALUE_OF_QUERY
- } /* if */
- } else {
- ERROR_NO_NAME_OF_QUERY
- } /* if */
- *format = scan;
- } /* if */
-
- *cptr = attn;
- attn = 0;
- } /* if */
- } /* for */
- writestring (outstream, cptr);
- return (TRUE);
-
- } /* flexprintf */
-
- #else /* !OLD */
-
-
- /*****************************************************************************
-
- NAME
- flexprintf
-
- PARAMETER
- STREAM*outstream;
- BOOL (*writestring)(STREAM*, STRPTR);
- ; we expect writestring to return <>0 on Success and
- ; 0 in case of any Failure.
- STRPTR tmplt;
- ; Format is destroyed during the scan, we cannot
- ; use const-strings in System with mem-protection
- STREAM*instream;
- STRPTR (*getstring)(STREAM*, STRPTR);
-
- RESULT
- success
-
- RETURN
- BOOL;
-
- DESCRIPTION
- similar to C/sprintf but slightly different in usage and syntax:
- while sending tmplt through "writestring(outstream,...)",
- we do replace occurancies of [$%][[(`{|<]char-seq[])'}>] with
- the string, that is returned by "getstring(instream, char-seq)";
- the meaning of [$%] can be escaped by duplicating the character.
-
-
- NOTES
- * tmplt MUST NOT be const! (see BUGS)
- for _flexprintf in any case and for flexprintf
- as long as FLEXPRINT_BUFFER is not defined to 1
-
- * not like in normal Shell- or XDME-scripts there MUST be a form
- of quotes around any variable!
-
- * formatting of replaced variables must be supported by the
- get-function, if such features are needed.
-
- * between the brackets of a variable-query there must be at least
- one char; empty variablenames are not allowed (also if Your getstring
- knows, what is wanted), and lead to a break.
-
- * getstring returning NULL means an error has occured; we will break
- for this reason. Empty strings should be given via "".
- Furthermore we do not free the strings gotten from getstring(),
- since we don't know, if they are static or not, so if these strings
- are dynamically created, You should store them in a static variable.
- my preferred way looks like the following:
- char *getvar(void *x, char *n) {
- static char *ptr = NULL;
- if (ptr) free(ptr);
- ptr = ...;
- return ptr;
- }
-
-
- * not terminating a query will cause a break, if there is no other
- query behind, else the result is not defined.
-
- * we use different macros to inticate the common errors, which are
- recognized: ERROR_NO_NAME_OF_QUERY, ERROR_NO_VALUE_OF_QUERY and
- ERROR_UNTERMINATED_QUERY, ERROR_NO_MEMORY; they are defined to do nothing, so You
- might want to redefine them to Your needs.
-
- Please note, that "%$" and "(`[{<«"/")']}>»" may be changed via some
- defines described below:
-
- * the macro "is_varstart" is used to recognize %/$ - You might want to
- redefine it according to Your needs (see above for different examples)
- if defined "SLOW_VARSTART" You can use the define "QUERY_START" to
- define a list of characters, which may be used as start of a query-
- indicator.
-
- * the defines "BRACKET_OPEN" and "BRACKET_CLOSE" can be used to define
- the different open-brackets and their corresponding close-brackets
- (see above for examples)
-
- * to gain more flexibility You may directly call _flexprintf()
- which has the additional parameters query_starts ("$%"),
- open_brackets ("([{...") and close_brackets (")]}...")
-
- BUGS
- * tmplt is temporarily destroyed during the scan. this is done,
- since we have no information about a necessary buffersize to
- keep a string in, but we wanted to use string-operations instead
- of character operations for writestring.
- (the described behaiviour can be changed (at least for flexprintf,
- not for _flexprintf) by defining FLEXPRINT_BUFFER to 1. (that toggle
- makes flexprintf create a copy of the template and send the copy
- to _flexprintf))
-
- EXAMPLES
-
- SEE ALSO
-
- INTERNALS
- * Funktionsweise:
- wir parsen ein template, das normalerweise
- $(...) oder %(...) oder ${...} oder %{...} oder
- $«...» oder %«...» oder $<...> oder %<...> oder
- $[...] oder %[...] oder $`...' oder %`...'
- als signalworte hat; sobald wir auf ein %/$ stossen, wird der
- bisher geparste und nicht ausgegebene Teil des templates nach
- writestring geschickt. Falls nach %/$ dann eine der Klammern kommt,
- wird, was zwischen den Klammern steht, an getstring uebergeben,
- dessen Ergebnis (wir erwarten IMMER strings) wird dann an
- writestring geschickt. Um die Bedeutung von %/$ zu loeschen
- muss das entsprechende Symbol dupliziert werden, nur eines der
- beiden wird dann ausgegeben. Falls keine bracket folgt, ist eine
- Verdopplung eigentlich unnoetig, sollte aber dennoch erfolgen.
-
- * Anwendung:
- man kann die Funktion auf 2 sehr unterschiediche
- Weisen verwenden:
- wie sprintf - in diesem Falle ignoriert die
- get-funktion das 2. Argument und gibt jedesmal den
- "naechsten" wert zurueck
- wie hier gedacht - in diesem falle liest die getfunktion
- aus einem baum o.ae. den Wert, der der namen von arg2 traegt.
-
-
- HISTORY
- 21-07-93 b_noll created
- 17-08-93 b_noll rewritten without "writechar()"
- 18-08-93 b_noll modified for XDME
- 01-05-94 b_null major rewrites ...
-
- ******************************************************************************/
-
-
- BOOL _flexprintf (STREAM* outstream, BOOL (*writestring)(STREAM*, STRPTR), STRPTR tmplt, STREAM* instream, STRPTR (*getstring)(STREAM*, STRPTR), const STRPTR query_starts, const STRPTR open_brackets, const STRPTR close_brackets) {
- unsigned char *memo = tmplt;
- unsigned char curr;
- unsigned char attn = 0;
-
- for (; (curr = *tmplt) != 0; ++tmplt) {
-
- /* ---- seems, that we are starting a query, output all chars up to here, mark the pos w/ memo */
- #ifdef SLOW_VARSTART
- if (strchr(query_starts, curr))
- #else
- if (is_varstart(curr))
- #endif
- {
-
- /* ---- previous char was the same? - then allow output of one of'em */
- /* that hack was done to allow something like escaping; now we */
- /* forbid a query by preceding it with two the same varstarts */
- if (curr == attn) {
- memo = tmplt;
- attn = 0;
- continue;
- } /* if */
-
- /* ---- output the tmplt up to this point and */
- /* mark the position with an additional ptr */
- /* keep also a copy of varstart to recognize */
- /* duplicates in order to ignore them */
-
- /* ---- we do temporarily modify tmplt here!!!! */
- *tmplt = 0;
- if (!writestring (outstream, memo)) {
- *tmplt = curr;
- return FALSE;
- } /* if */
- *tmplt = curr;
-
- memo = tmplt;
- attn = curr;
- continue;
- } /* if varstart */
-
- if (attn) {
- unsigned char scan = 0;
-
- attn = 0;
-
- /* ---- check, if the current character is an open-bracket */
- /* and get the close-bracket, that is correponding to */
- /* this open-bracket */
- {
- int i;
- for (i = 0; open_brackets[i]; ++i) {
- if (curr == open_brackets[i]) {
- scan = close_brackets[i];
- break;
- } /* if */
- } /* for */
- }
-
- /* ---- we found a bracket after var_start */
- if (scan) {
- char * rslt;
-
- /* ---- skip the open-bracket */
- ++tmplt;
-
- /* ---- seach the close-bracket */
- while ((curr = *tmplt) && !(curr == scan))
- ++tmplt;
-
- /* ---- make sure we have found a terminating close-bracket */
- if (!curr) {
- ERROR_UNTERMINATED_QUERY
- return FALSE;
- } /* if */
-
- /* ---- make sure we have got at least one char */
- /* between the backets */
- if (tmplt == memo + 2) {
- ERROR_NO_NAME_OF_QUERY
- return FALSE;
- } /* if */
-
- /* ---- query for the variable described between */
- /* the brackets */
-
- /* ---- here we do temporarily modify tmplt!!! */
- *tmplt = 0;
- rslt = getstring (instream, memo + 2);
- *tmplt = scan;
-
- /* ---- make sure we got a valid string from getstring() */
- if (!rslt) {
- ERROR_NO_VALUE_OF_QUERY
- return FALSE;
- } /* if !rslt */
-
- /* ---- output the resultstring */
- if (!writestring (outstream, rslt))
- return FALSE;
-
- memo = tmplt+1;
- } /* if bracket */
- } /* if attn */
- } /* for */
-
- if (!writestring (outstream, memo))
- return FALSE;
-
- return TRUE;
- } /* _flexprintf */
-
-
-
- BOOL flexprintf (STREAM* outstream, BOOL (*writestring)(STREAM*, STRPTR), STRPTR tmplt, STREAM* instream, STRPTR (*getstring)(STREAM*, STRPTR)) {
- #if defined(FLEXPRIN_BUFFER) && FLEXPRINT_BUFFER
- char *dup;
- BOOL rslt;
-
- if (NULL == (dup = strdup(tmplt))) {
- ERROR_NO_MEMORY
- return FALSE;
- } /* if */
- rslt = _flexprintf(outstream, writestring, dup, instream, getstring, QUERY_START, BRACKET_OPEN, BRACKET_CLOSE);
- free (dup);
- return rslt;
- #else
- return _flexprintf(outstream, writestring, tmplt, instream, getstring, QUERY_START, BRACKET_OPEN, BRACKET_CLOSE);
- #endif
- } /* flexprintf */
-
-
- #endif /* OLD */
-
-
-
-
-
-
-
-
-
- /*****************************************************************************
-
- NAME
- read_file
-
- PARAMETER
- char* tpltname;
-
- RESULT
- success;
-
- RETURN
- BOOL;
-
- DESCRIPTION
- lese ein file ein,
- bearbeite es nach den Vorgaben
- und fuege es in den aktuellen kontext ein
-
- NOTES
- beim einlesen des Files werden alle zeilen, die mit
- $$ (oder %%) beginnen separat interpretiert, und nicht
- wieder ausgegeben.
-
- BUGS
-
- EXAMPLES
-
- SEE ALSO
-
- INTERNALS
-
- HISTORY
- 21-07-93 b_noll created for TEMPLATER
- 18-08-93 b_noll modified for XDME
-
- ******************************************************************************/
-
- BOOL read_file (char* name)
- {
- char * buffer;
- char * b2;
- FILE * fi;
- long len;
- BOOL success = FALSE;
-
- if (name && *name) {
- if ((buffer = malloc(MAXLINELEN))) {
- if ((fi = fopen (name, "r"))) {
- success = TRUE;
- while (success && (len = xefgets (fi, buffer, MAXLINELEN)) >= 0) {
- b2 = buffer;
- /* printf (">%s",buffer); */
- if (is_command(b2)) {
- if (is_comment(buffer+2)) continue;
- success = do_command (buffer+2);
- } else {
- b2 = buffer + len;
- *b2 = '\n';
- ++b2;
- *b2 = 0;
-
- success = flexprintf (NULL, (APTR)myfputs, buffer, NULL, (APTR)mygetv);
-
- } /* if */
- } /* while */
- fclose (fi);
- } else {
- ERROR_NO_FILE
- } /* if */
-
- free (buffer);
- } else {
- nomemory();
- } /* if */
- } /* if */
- return (success);
- } /* read_file */
-
- /***************************************************
- XDME ADAPTION 18-08-93
- ***************************************************/
-
-
- /* get a variable - XDME ignores arg1 */
- /* currently (20-10-93) we can NOT use a const char* name */
-
- #if 1
-
-
- char* mygetv (APTR db, char* name)
- {
- static char tmp_buf[256];
- int len;
- char*template = "%s";
-
- /* PrintF ("mygetVAR: <%s>\n", name); */
-
- if (!name) return (NULL);
-
- strcpy (tmp_buf, name);
- name = tmp_buf;
-
- len = strlen (name);
-
- { /* cut trailing whitespace */
- char * dummy;
- dummy = name + len - 1;
-
- while (dummy > name && isspace(*dummy)) {
- *dummy = 0;
- --dummy;
- } /* while */
- }
-
- while (isspace(*name)) {++name;}
-
- {
- char* dummy = name;
-
- /* find postpended SPRINTF-tplt */
- while (*dummy && (*dummy != ':')) ++dummy;
- if (*dummy && dummy[1]) { /* has a postpended sPrintF - template */
- template = dummy + 1;
-
- /* Remove Whitespace between name and Template */
- --dummy;
- while (isspace(*dummy) && dummy > name) --dummy;
- ++dummy;
- *dummy = 0;
- } /* if */
- }
-
- {
- if ((name = getvar(name))) {
- sprintf (tmp_buf, template, name, name, name, name);
- return (tmp_buf);
- } /* if */
- }
-
-
-
- return (NULL);
- } /* mygetv */
-
- #else
-
- char* mygetv (APTR* db, char* name)
- {
- char * x;
- #if 0
- if (x = getvar (name)) {
- strcpy (tmp_buffer, x);
- free (x);
- return (tmp_buffer);
- } else
- #endif
- {
- char* dummy = name;
- char* tpl = "%s";
- char sec;
-
- /* find postpended SPRINTF-tplt */
-
- while (*dummy && (*dummy != ':')) ++dummy;
- if (*dummy && dummy[1]) { /* has a postpended sPrintF - template */
- tpl = dummy + 1;
- } /* if */
-
- #if 0
- /* Remove Whitespace between name and Template */
- --dummy;
- while (isspace(*dummy) && dummy > name) --dummy;
- ++dummy;
- #endif
- sec = *dummy;
- *dummy = 0;
-
- if ((x = getvar (name))) {
- sprintf(tmp_buffer, tpl, x);
- free (x);
- return (tmp_buffer);
- } /* if */
- *dummy = sec;
- } /* if */
- return (NULL);
- } /* mygetv */
-
- #endif
-
-
-
- /* output a string - XDME ignores arg1 */
-
- BOOL myfputs (APTR out, char* str)
- {
- if (!*str) return (TRUE);
- av[0] = "insert";
- av[1] = str;
- do_insertwrite();
- return (BOOL)!IS_ABORTED();
- } /* myfputs */
-
-
-
-
- /***************************************************
- XDME COMMAND INTERFACE 18-08-93
- ***************************************************/
-
- /*DEFLONG #long READTEMPLATE
-
- This command inserts @{B}file@{UB}.
- passing all lines starting with "$$" to EVAL
- (lines starting with "$$#" are ignored) and
- replacing all "$(...)" and "$`...'" by their
- values if matching variables do exist.
-
- That function might be very useful for
- handling very formalistic structs, which
- do need only little work by user.
-
- Since the parse is line-oriented, usage of
- linefeeds inside "$(...)" and "$`...' is
- forbidden; however expanded values might
- contain linefeeds
-
- */
-
- /*DEFHELP #cmd textedit,io READTEMPLATE filename - read in a file and replace all occurencies of $(varname) with the contents of that varname */
-
- DEFUSERCMD("ReadTemplate", 1, CF_ICO, int, do_readtplt, (void),)
- {
- read_file (av[1]);
- return (1);
- } /* do_readtplt */
-
-
-
-
- #ifdef STATIC_COM
-
- COMMAND("readtemplate", 1, CF_ICO, (FPTR)do_readtplt )
-
- #endif
-
-
- /******************************************************************************
- ***** END tplter.c
- ******************************************************************************/
-
-